---
title: "Cloudflare Provider"
description: "This guide walks you through setting up `hot-updater` with Cloudflare in a React Native project. You'll configure the environment, install required packages, and initialize Cloudflare for seamless updates."
icon: cloudflare
---

import { Tabs, Tab } from 'fumadocs-ui/components/tabs';
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';

<video src={"/docs/get-started/init-cloudflare.mp4"} controls autoPlay loop muted />

## Prerequisites

Before you begin, make sure the following are ready:
- **Node.js**: Version 20 or later is recommended.
- **Cloudflare Account**: Sign up at [Cloudflare](https://cloudflare.com) if you don't have one.
- **Cloudflare API Token**: Create an API Token at https://dash.cloudflare.com/{your-account-id}/api-tokens with **R2 Edit** & **D1 Edit** permissions

## Step 1: Install Required Packages

Run the following command to install dependencies:

```package-install
npm install hot-updater --save-dev
```

## Step 2: Configure Cloudflare

Run the initialization script to start the interactive setup process. Use the following command with your preferred package manager:

```package-install
npx hot-updater init
```

<Accordions type="single">
  <Accordion title="Interactive Setup Steps">

1. **Select a Build Plugin**: Choose a build plugin for your project (e.g., Bare (React Native CLI) for React Native).
2. **Select a Provider**: Select Cloudflare as the provider for handling updates.

During the setup, you will be prompted to:
1. **Login to Cloudflare**: Sign in to your Cloudflare account with wrangler
2. **Enter R2 & D1 API Token**: Input your API token with R2 and D1 permissions
3. **Select R2 Bucket**: Choose an existing R2 bucket or create a new one
4. **Select D1 Database**: Choose an existing D1 database or create a new one
5. **Run D1 Migration**: Execute database migrations for D1
6. **Deploy Worker**: Deploy the Cloudflare Worker for update management

  </Accordion>
</Accordions>

Once the setup is complete, a `.env` file will be generated containing the following keys:

```
HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID=your-account-id
HOT_UPDATER_CLOUDFLARE_R2_BUCKET_NAME=your-r2-bucket-name
HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID=your-d1-database-id
HOT_UPDATER_CLOUDFLARE_API_TOKEN=your-api-token
```



<Callout type="warn">

If you're **not** using the `react-native-dotenv` solution, the tokens from your `.env` file will not be included in your app bundle and are therefore not exposed to risks. However, if you're still concerned,

please refer to the article below for more details:
[Security](/docs/policy/security#plugin-token-protection)
</Callout>


## Step 3: Generated Configurations
During the initialization process, the following file is automatically generated:

- `hot-updater.config.ts`: This file contains the configuration settings for integrating Cloudflare with your project.

```ts title="hot-updater.config.ts"
import { bare } from "@hot-updater/bare";
import { d1Database, r2Storage } from "@hot-updater/cloudflare";
import { defineConfig } from "hot-updater";
import { config } from "dotenv";

config({ path: ".env.hotupdater" });

export default defineConfig({
  build: bare({ enableHermes: true }),
  storage: r2Storage({
    bucketName: process.env.HOT_UPDATER_CLOUDFLARE_R2_BUCKET_NAME!,
    accountId: process.env.HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID!,
    cloudflareApiToken: process.env.HOT_UPDATER_CLOUDFLARE_API_TOKEN!,
  }),
  database: d1Database({
    databaseId: process.env.HOT_UPDATER_CLOUDFLARE_D1_DATABASE_ID!,
    accountId: process.env.HOT_UPDATER_CLOUDFLARE_ACCOUNT_ID!,
    cloudflareApiToken: process.env.HOT_UPDATER_CLOUDFLARE_API_TOKEN!,
  }),
});

```

## Step 4: Add HotUpdater to Your Project

The HotUpdater component wraps your application, enabling seamless delivery of updates and fallback UI during updates. Follow these steps to integrate it into your App.tsx:

```tsx title="App.tsx"
import { HotUpdater } from "@hot-updater/react-native";

function App() {
  return (
    <View>
      <Text>Hello World</Text>
    </View>
  );
}

export default HotUpdater.wrap({
  baseURL: "https://<your-worker-name>.<your-subdomain>.workers.dev/api/check-update", // [!code ++]
  updateStrategy: "appVersion", // or "fingerprint" // [!code ++]
  updateMode: "auto",
  requestHeaders: {
    // if you want to use the request headers, you can add them here
  },
  fallbackComponent: ({ progress, status }) => (
    <View
      style={{
        flex: 1,
        padding: 20,
        borderRadius: 10,
        justifyContent: "center",
        alignItems: "center",
        backgroundColor: "rgba(0, 0, 0, 0.5)",
      }}
    >
      {/* You can put a splash image here. */}

      <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
        {status === "UPDATING" ? "Updating..." : "Checking for Update..."}
      </Text>
      {progress > 0 ? (
        <Text style={{ color: "white", fontSize: 20, fontWeight: "bold" }}>
          {Math.round(progress * 100)}%
        </Text>
      ) : null}
    </View>
  ),
})(App);

```

## Step 5: Add Babel / Re.Pack / Expo Plugin to Your Project

In this step, you will configure Babel to set the bundle ID at build time. This is necessary for integrating the `hot-updater` plugin into your project.

<Tabs items={['Bare (Babel)', 'Re.Pack', 'Expo']}>
  <Tab value="Bare (Babel)">

Add the following to your `babel.config.js` file:
```js title="babel.config.js"
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    'hot-updater/babel-plugin', // [!code ++]
  ],
};

```
</Tab>
<Tab value="Re.Pack">
Add the following to your `rspack.config.mjs` file:
```package-install
-updater/repack
```

```js title="rspack.config.mjs"
import { HotUpdaterPlugin } from "@hot-updater/repack";

export default {
  // ...
  plugins: [
    new Repack.RepackPlugin(),
    new HotUpdaterPlugin() // [!code ++]
  ],
};
```
</Tab>

<Tab value="Expo">

Add the plugin to your `app.json` file as shown below:

```json title="app.json"
{
  "expo": {
    "plugins": [
      [
        "@hot-updater/react-native",
        {
          "channel": "production"
        }
      ]
    ]
  }
}
```

```package-install
npx expo prebuild
```

Run the following command to customize your Babel configuration:

```package-install
npx expo customize babel.config.js
```

Add the following to your `babel.config.js` file:

```js title="babel.config.js"
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    'hot-updater/babel-plugin', // [!code ++]
  ],
};
```

<Callout>
This process automatically generates the code that needs to be added in Step 6.
</Callout>

</Tab>
</Tabs>


## Step 6: Add Native Code

To complete the integration of `hot-updater`, you'll need to add native code modifications for both Android and iOS platforms. This step ensures the `hot-updater` can interact with your app's underlying framework to apply updates seamlessly.

### Android

<Tabs items={['Kotlin (RN 0.82+)', 'Kotlin', 'Java']}>
  <Tab value="Kotlin (RN 0.82+)">
    ```kt title="android/app/src/main/java/com/<your-app-name>/MainApplication.kt"
    package com.hotupdaterexample

    import android.app.Application
    import com.facebook.react.PackageList
    import com.facebook.react.ReactApplication
    import com.facebook.react.ReactHost
    import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
    import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
    import com.hotupdater.HotUpdater

    class MainApplication : Application(), ReactApplication {

    override val reactHost: ReactHost by lazy {
      getDefaultReactHost(
        context = applicationContext,
        packageList =
          PackageList(this).packages.apply {
            // Packages that cannot be autolinked yet can be added manually here, for example:
            // add(MyReactNativePackage())
          },
        jsBundleFilePath = HotUpdater.getJSBundleFile(applicationContext), // [!code ++]
      )

    }

    override fun onCreate() {
      super.onCreate()
      loadReactNative(this)
    }
    }
    ```

  </Tab>
  <Tab value="Kotlin">
```kt title="android/app/src/main/java/com/<your-app-name>/MainApplication.kt"
package com.hotupdaterexample

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
import com.hotupdater.HotUpdater // [!code ++]

class MainApplication : Application(), ReactApplication {

  override val reactNativeHost: ReactNativeHost =
      object : DefaultReactNativeHost(this) {
        override fun getPackages(): List<ReactPackage> =
            PackageList(this).packages.apply {
              // Packages that cannot be autolinked yet can be added manually here, for example:
              // add(MyReactNativePackage())
            }

        override fun getJSMainModuleName(): String = "index"

        override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

        override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
        override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED

        override fun getJSBundleFile(): String? {  // [!code ++]
          return HotUpdater.getJSBundleFile(applicationContext)  // [!code ++]
        }  // [!code ++]
      }

  override val reactHost: ReactHost
    get() = getDefaultReactHost(applicationContext, reactNativeHost)

  override fun onCreate() {
    super.onCreate()
    SoLoader.init(this, OpenSourceMergedSoMapping)
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      load()
    }
  }
}
```
  </Tab>
  <Tab value="Java">
  ```java title="android/app/src/main/java/com/<your-app-name>/MainApplication.java"

package com.hotupdaterexample;

import android.app.Application;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import java.util.List;
import com.hotupdater.HotUpdater;  // [!code ++]

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost =
      new DefaultReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          return "index";
        }

        @Override // [!code ++]
        protected String getJSBundleFile() {  // [!code ++]
            return HotUpdater.Companion.getJSBundleFile(this.getApplication().getApplicationContext());  // [!code ++]
        }  // [!code ++]

        @Override
        protected boolean isNewArchEnabled() {
          return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
        }

        @Override
        protected Boolean isHermesEnabled() {
          return BuildConfig.IS_HERMES_ENABLED;
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);

    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      DefaultNewArchitectureEntryPoint.load();
    }
    ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }
}

```

  </Tab>
</Tabs>

### iOS

<Tabs items={['Swift', 'Objective-C']}>
<Tab value="Swift">
```swift title="ios/<your-app-name>/AppDelegate.swift"
import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import HotUpdater // [!code ++]

@main
class AppDelegate: RCTAppDelegate {
  override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    self.moduleName = "HotUpdaterExample"
    self.dependencyProvider = RCTAppDependencyProvider()

    // You can add your custom initial props in the dictionary below.
    // They will be passed down to the ViewController used by React Native.
    self.initialProps = [:]

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  override func sourceURL(for bridge: RCTBridge) -> URL? {
    self.bundleURL()
  }

  override func bundleURL() -> URL? {
#if DEBUG
    RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
    Bundle.main.url(forResource: "main", withExtension: "jsbundle") // [!code --]
    HotUpdater.bundleURL() // [!code ++]
#endif
  }
}

```
</Tab>
<Tab value="Objective-C">
```objc title="ios/<your-app-name>/AppDelegate.mm"
#import "AppDelegate.h"
#import <HotUpdater/HotUpdater.h> // [!code ++]
#import <React/RCTBundleURLProvider.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.moduleName = @"HotUpdaterExample";
  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};

  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
  return [self bundleURL];
}

- (NSURL *)bundleURL
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; // [!code --]
  return [HotUpdater bundleURL]; // [!code ++]
#endif
}

@end
```
</Tab>
</Tabs>


## Verifying the Setup
1. Check your Cloudflare dashboard for the newly created bucket, D1 database, and worker.
2. Test the HotUpdater integration in your React Native app.


You're all set! 🎉 Start using hot-updater with Cloudflare for seamless updates in your React Native app.

This document simplifies the initialization process, making it easy for developers to get started with minimal friction.
